package com.dog.framework.core.utils;

import cn.hutool.core.codec.Base64;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.dog.framework.core.constant.SecurityConstants;
import com.dog.framework.core.model.JwtUser;
import lombok.extern.slf4j.Slf4j;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author liuxk
 * @date 2024/1/2 17:27
 *
 */
@Slf4j
public class JwtUtils {

    /**
     * token过期时间
     */
    public static Integer JWT_EXPIRE_TIME = 15 * 24 * 60 * 60 * 1000;

    /**
     * 生成密钥
     *
     * @return 生成密钥
     */
    public static Algorithm getAlgorithm() {
        return Algorithm.HMAC256(SecurityConstants.TOKEN_JWT_KEY);
    }


    public static String generateToken(JwtUser jwtUser) {
        Long userId = jwtUser.getUserId();
        String userName = jwtUser.getUsername();
        String password = jwtUser.getPassword();
        Long orgId = jwtUser.getOrgId();
        Long tenantId = jwtUser.getTenantId();
        List<String> userRoles = jwtUser.getRoleCodeList();
        List<Long> dataScopes = jwtUser.getDataScopeList();

        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MILLISECOND, JWT_EXPIRE_TIME);
        return JWT.create().withClaim(SecurityConstants.JWT_USER_ID, userId).withClaim(SecurityConstants.JWT_USERNAME
                , userName).withClaim(SecurityConstants.JWT_PASSWORD, password).withClaim(SecurityConstants.JWT_ORG_ID, orgId).withClaim(SecurityConstants.JWT_TENANT_ID, tenantId).withClaim(SecurityConstants.JWT_USER_ROLE, userRoles).withClaim(SecurityConstants.JWT_DATA_SCOPE, dataScopes).withClaim(SecurityConstants.JWT_JTI, UuIdUtils.fastSimpleUUID()).withExpiresAt(calendar.getTime()).sign(getAlgorithm());
    }


    /**
     * 生成token
     *
     * @param userId   用户id
     * @param userName 用户名
     * @param userRoles 用户的角色
     * @return token jwtToken
     */
    public static String generateToken(Long userId, String userName, String password, Long orgId, Long tenantId,
            List<String> userRoles, List<Long> dataScopes) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MILLISECOND, JWT_EXPIRE_TIME);
        return JWT.create().withClaim(SecurityConstants.JWT_USER_ID, userId).withClaim(SecurityConstants.JWT_USERNAME
                , userName).withClaim(SecurityConstants.JWT_PASSWORD, password).withClaim(SecurityConstants.JWT_ORG_ID, orgId).withClaim(SecurityConstants.JWT_TENANT_ID, tenantId).withClaim(SecurityConstants.JWT_USER_ROLE, userRoles).withClaim(SecurityConstants.JWT_DATA_SCOPE, dataScopes).withClaim(SecurityConstants.JWT_JTI, UuIdUtils.fastSimpleUUID()).withExpiresAt(calendar.getTime()).sign(getAlgorithm());
    }


    /**
     * 解码token
     *
     * @param token jwtToken
     * @return 用户信息
     */
    public static JwtUser decode(String token) {
        JwtUser jwtUser = new JwtUser();
        DecodedJWT decodedJWT = JWT.require(getAlgorithm()).build().verify(token);
        Map<String, Claim> jwt = decodedJWT.getClaims();
        Long userId = jwt.get(SecurityConstants.JWT_USER_ID).asLong();
        Long orgId = jwt.get(SecurityConstants.JWT_ORG_ID).asLong();
        Long tenantId = jwt.get(SecurityConstants.JWT_TENANT_ID).asLong();
        String userName = jwt.get(SecurityConstants.JWT_USERNAME).asString();
        String password = jwt.get(SecurityConstants.JWT_PASSWORD).asString();
        List<String> roles = jwt.get(SecurityConstants.JWT_USER_ROLE).asList(String.class);
        List<Long> dataScopes = jwt.get(SecurityConstants.JWT_DATA_SCOPE).asList(Long.class);
        String jti = jwt.get(SecurityConstants.JWT_JTI).asString();
        Long expireIn = getExpiresIn(decodedJWT);
        jwtUser.setUserId(userId);
        jwtUser.setUsername(userName);
        jwtUser.setPassword(password);
        jwtUser.setOrgId(orgId);
        jwtUser.setTenantId(tenantId);
        jwtUser.setJti(jti);
        jwtUser.setExpireIn(expireIn);
        jwtUser.setRoleCodeList(roles);
        jwtUser.setDataScopeList(dataScopes);
        return jwtUser;
    }

    private static Map<String, Claim> getTokenBody(String token) {
        return getDecodedJWT(token).getClaims();
    }

    private static DecodedJWT getDecodedJWT(String token) {
        return JWT.require(getAlgorithm()).build().verify(token);
    }


    public static String getJwtJti(String token) {
        return getTokenBody(token).get(SecurityConstants.JWT_JTI).asString();
    }

    public static Long getExpiresIn(DecodedJWT decodedJWT) {
        Date expiration = decodedJWT.getExpiresAt();
        return expiration != null ? Long.valueOf((expiration.getTime() - System.currentTimeMillis()) / 1000L).longValue() : 0L;
    }

    //是否已过期
    public static boolean isExpiration(String token) {
        try {
            return getDecodedJWT(token).getExpiresAt().before(new Date());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return true;
    }


    public static List<String> getRoleCodeList(String token) {
        return getTokenBody(token).get(SecurityConstants.JWT_USER_ROLE).asList(String.class);
    }


    public static void main(String[] args) {
        JwtUser tagetUser = new JwtUser();
        tagetUser.setUserId(10001L);
        tagetUser.setUsername("liuxk");
        tagetUser.setPassword("$2a$10$hYhqzboPK3rvd.mCcaVGuO3GmGMx9D6Ubptx.9Tr9OwI02nKTPeMG");
        tagetUser.setOrgId(10L);
        tagetUser.setTenantId(1001L);
        tagetUser.setRoleCodeList(Stream.of("common", "admin").collect(Collectors.toList()));
        tagetUser.setDataScopeList(Stream.of(1L, 2L).collect(Collectors.toList()));

        // 生成token
        String token = JwtUtils.generateToken(tagetUser);
        log.info("token is : {}", token);

        JwtUser jwtUser = decode(token);
        log.info("getUserId. {}", jwtUser.getUserId());
        log.info("getUsername. {}", jwtUser.getUsername());
        log.info("getOrgId. {}", jwtUser.getOrgId());
        log.info("getTenantId. {}", jwtUser.getTenantId());
        log.info("getRoles. {}", jwtUser.getRoleCodeList());
        log.info("getDataScopes. {}", jwtUser.getDataScopeList());


        //7.将解析后的token加密放入请求头中，方便下游微服务解析获取用户信息
        String base64 = Base64.encode(JsonUtils.toJsonString(jwtUser));
        log.info("base64 is {}", base64);

        String json = Base64.decodeStr(base64);
        JwtUser jwtUser1 = JsonUtils.parseObject(json, JwtUser.class);
        log.info("getUserId. {}", jwtUser1.getUserId());
        log.info("getUsername. {}", jwtUser1.getUsername());
        log.info("getOrgId. {}", jwtUser1.getOrgId());
        log.info("getTenantId. {}", jwtUser1.getTenantId());
        log.info("getRoles. {}", jwtUser1.getRoleCodeList());
        log.info("getDataScopes. {}", jwtUser1.getDataScopeList());


    }


}
